#include "printer.h"
#include <QJsonParseError>
#include <QJsonArray>
#include <QImage>
#include <QNetworkProxy>
#include <QPainter>
#include <QTcpSocket>
#include <QAbstractSocket>
#include "utils.h"
#include "tsplcmd.h"
#include "netprinter.h"
#include "usbprinter.h"


PrinterComponent* PrinterComponent::FromJson(QJsonObject &obj){
    PrinterComponent* component = new PrinterComponent();

    component->x = GetString(obj, "x").toInt();
    component->y = GetString(obj, "y").toInt();
    component->h = GetString(obj, "h").toInt();
    component->w = GetString(obj, "w").toInt();
    component->fontSize = GetString(obj, "fontSize").toInt();
    component->fontWeight = GetBool(obj, "fontWeight");
    component->textAlign = GetString(obj, "textAlign");
    component->name = GetString(obj, "name");
    component->value = GetString(obj, "value");
    // qDebug()<< "value: " << component->value;
    return component;
}

QString PrinterComponent::getText(Record &r) {
    static QStringList stringlist = {
        "$name",
        "$makeAt",
        "$vailAt",
        "$description",
        "$saveType",
        "$remark",
        "xxx"
    };

    QString text;
    switch (stringlist.indexOf(value)){
    case 0:
        text = r.Name;
        break;
    case 1:
    {
        QDateTime time = QDateTime::fromSecsSinceEpoch(r.MakeAt);
        text = time.toString("yyyy年MM月dd日 ddd HH:mm");
    }
    break;
    case 2:
        text = r.GetValidityTimeString();
    break;
    case 3:
        text = QString("%1, %2").arg(GetOperationTypeString(r.OperationType))
                   .arg(GetValidityCountString(r.DateUnit, r.DateCount));
        break;
    case 4:
        text = r.GetSaveTypeString();
        break;
    case 5:
        text = r.Remark;
        break;
    case 6:
        text = name;
        break;
    case -1:
        text = name;
    }
    return text;
}

void PrinterComponent::Draw(QPainter &painter, Record &r){
    QString text = getText(r);
    if (text.isEmpty())
        return;

    // qDebug() << "Printer Text: " << value <<  text << fontSize;

    // QFont font("Microsoft YaHei");
    // QFont font("Microsoft JhengHei");
    QFont font;
    font.setStyleStrategy(QFont::NoAntialias);
    font.setWeight(QFont::Bold);

    // 绘制品名
    font.setBold(fontWeight);
    font.setPointSize(fontSize);
    QRect rect(x, y, w, h);
    painter.setFont(font);

    int align = Qt::AlignTop | Qt::TextWordWrap;
    if (textAlign == "left") {
        align |= Qt::AlignLeft;
    } else if (textAlign == "right") {
        align |= Qt::AlignRight;
    } else {
        align |= Qt::AlignCenter;
    }
    painter.drawText(rect, align, text);
    return;
}

Printer::Printer(QObject *parent)
    : QObject{parent}
{
}

void Printer::SetPrinterInfo(
    int PrinterDpi,
    QString PrinterName,
    QString PrinterIp,
    QString PrinterPort,
    int HShift,
    int VShift,
    QString PrinterXML,
    QString PrinterTemplateVersion){

    isSuccess = true;
    dpi = PrinterDpi;
    if (dpi == 0) {
        dpi = 8;
    }
    name = PrinterName;
    ip = PrinterIp;
    port = PrinterPort.toInt();
    hShift = HShift * dpi;
    vShift = VShift * dpi;
    templateVersion = PrinterTemplateVersion;
    QByteArray encodeData = PrinterXML.toUtf8();
    QByteArray decodeData = QByteArray::fromBase64(encodeData);
    // qDebug() << "PrinterXML: " << QString(decodeData);
    QJsonParseError parseError;
    QJsonDocument doc = QJsonDocument::fromJson(decodeData, &parseError);
    if (parseError.error != QJsonParseError::NoError) {
        isSuccess = false;
        emit printerFailed("打印模板解析错误：" + parseError.errorString());
        return;
    }
    if (!doc.isObject()){
        // qDebug() << "PrinterXML: " << QString(decodeData);
        emit printerFailed("打印模板格式错误");
        return;
    }

    QJsonObject root = doc.object();

    width = GetString(root, "width").toInt();
    height = GetString(root, "height").toInt();
    if (width < 30 || height < 30) {
        isSuccess = false;
        emit printerFailed("打印模板纸张尺寸不正确。");
        return;
    }

    if (!root["components"].isArray()) {
        isSuccess = false;
        emit printerFailed("打印模板格式不正确。");
        return;
    }

    QJsonArray list = root["components"].toArray();
    for (auto value: list) {
        if (value.isObject()) {
            auto obj = value.toObject();
            auto component = PrinterComponent::FromJson(obj);
            if (component != nullptr) {
                components.append(component);
            }
        }
    }

    if (components.isEmpty()) {
        isSuccess = false;
        emit printerFailed("打印模板格式不正确。");
        return;
    }

    client = createPrinter(ip, port);
    if (client == nullptr) {
        emit printerFailed("打印机配置错误。");
        return;
    }
    connect(client, &PrinterClient::dataSent, [=]{
        qDebug() << "打印数据发送成功";
    });
    connect(client, &PrinterClient::errorOccurred, [=](const QString& error){
        qCritical() << "打印失败:" << error;
        emit printerFailed(error); // 需要添加printError信号
    });
    return;
};

PrinterClient* Printer::createPrinter(QString ip, int port) {
    PrinterClient* client = nullptr;
    //Todo: 兼容不同打印机
    static QRegularExpression ipRegex("^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$");
    if (ipRegex.match(ip).hasMatch()) {
        auto printer = new NetPrinter();
        printer->setAddress(ip, port);
        client = printer;
        qDebug() << "打开网络打印机：" << ip << ":" << port;
    } else {
            auto printer = new UsbPrinter();
            printer->setPrinter(ip);
            client = printer;
            qDebug() << "打开USB打印机：" << ip;
    }

    return client;
}

QImage Printer::drawImage(Record& record){
    int w = width * dpi;
    int h = height * dpi;
    QImage image(w, h, QImage::Format_ARGB32);
    image.fill(Qt::white);
    QPainter painter(&image);
    painter.setRenderHint(QPainter::Antialiasing, false);
    painter.setRenderHint(QPainter::TextAntialiasing, false);
    painter.setPen(Qt::black);

    for (auto compnent: components) {
        compnent->Draw(painter, record);
    }

    QImage grayImage = image.convertToFormat(QImage::Format_Mono);
    return grayImage;
}

QByteArray Printer::getBitArray(QImage &grayImage){
    QByteArray pixelData;

    grayImage.invertPixels(QImage::InvertRgb);
    // 计算每行字节数（考虑内存对齐）
    int bytesPerLine = (grayImage.width() * grayImage.depth() + 31) / 32 * 4;
    pixelData.resize(bytesPerLine * grayImage.height());

    // 复制数据
    uchar* dst = reinterpret_cast<uchar*>(pixelData.data());
    const uchar* src = grayImage.constBits();
    memcpy(dst, src, pixelData.size());
    return pixelData;
}

void Printer::sendToPrinter(QByteArray &byte){
    TsplCmd cmd;
    cmd.PageSize(width, height)
        ->Gap(2)
        ->Speed(4)
        ->Density(7)
        ->Direction(1, 0)
        ->Reference(hShift, vShift)
        ->Cls()
        ->DrawBitmap(byte, width, height, dpi)
        ->End()
        ->SendToDevice(client);
}

void Printer::PrintRecord(Record& record){
    if (!isSuccess) {
        emit printerFailed("打印机配置错误，无法打印。");
        return;
    }

    QImage grayImage = drawImage(record);
    // grayImage.save("output.bmp", "BMP");
    auto byte = getBitArray(grayImage);
    sendToPrinter(byte);
};
